package com.welson.db.cryptor.wrapper;

import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * 支持加密字段的QueryWrapper
 * <p>
 * 注意：当使用select查询部分字段时，实体类必须要有无参构造方法，否则会类型转换失败
 *
 * @author welson
 */
public class EncryptQueryWrapper<T> extends AbstractEncryptWrapper<T, String, EncryptQueryWrapper<T>> implements Query<EncryptQueryWrapper<T>, T, String> {

    private final SharedString sqlSelect;

    public EncryptQueryWrapper() {
        this.sqlSelect = new SharedString();
        super.setEntity(null);
        super.initNeed();
    }

    @Override
    protected EncryptQueryWrapper<T> instance() {
        return new EncryptQueryWrapper<>();
    }

    @Override
    public final EncryptQueryWrapper<T> select(String... columns) {
        return select(Arrays.asList(columns));
    }

    public EncryptQueryWrapper<T> select(List<String> columns) {
        if (CollectionUtils.isNotEmpty(columns)) {
            this.sqlSelect.setStringValue(String.join(StringPool.COMMA, columns));
        }
        return typedThis;
    }

    @Override
    public EncryptQueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {
        super.setEntityClass(entityClass);
        this.sqlSelect.setStringValue(TableInfoHelper.getTableInfo(getEntityClass()).chooseSelect(predicate));
        return typedThis;
    }

    /**
     * 返回一个支持 lambda 函数写法的 wrapper
     */
    public EncryptLambdaQueryWrapper<T> lambda() {
        return new EncryptLambdaQueryWrapper<>(getEntity(), getEntityClass(), sqlSelect, paramNameSeq, paramNameValuePairs,
                expression, paramAlias, lastSql, sqlComment, sqlFirst);
    }

    @Override
    public String getSqlSelect() {
        return sqlSelect.getStringValue();
    }

    @Override
    public void clear() {
        super.clear();
        sqlSelect.toNull();
    }
}